// server main.c
#include "connect.h"
#include "my_header.h"
#include "threadPool.h"
#include "transFile.h"
#include <mysql/mysql.h>
#include <stdio.h>

#include "server_user.h"
#include "taskQueue.h"
#define MAX_CLIENTS 1024
#define LOG_FILE "server.log"

// 日志
void write_log(const char *format, ...)
{
    FILE *logFile = fopen(LOG_FILE, "a");
    if (!logFile)
    {
        perror("Failed to open log file");
        return;
    }

    time_t now = time(NULL);
    struct tm *t = localtime(&now);
    fprintf(logFile, "[%04d-%02d-%02d %02d:%02d:%02d] ", t->tm_year + 1900,
            t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);

    // valist
    va_list args;
    va_start(args, format);
    vfprintf(logFile, format, args);
    va_end(args);

    fprintf(logFile, "\n");
    fclose(logFile);
}

int exitPipe[2];
void handler(int signum)
{
    printf("signum = %d\n", signum);
    write_log("Parent process exiting.");
    int res = write(exitPipe[1], "1", 1);
    if (res == -1)
    {
        perror("write");
    }
}

int main()
{
    // parent process
    pipe(exitPipe);
    if (fork())
    {
        close(exitPipe[0]);
        signal(SIGUSR1, handler); // SIGUSR1 = 10
        wait(NULL);
        exit(0);
    }

    // subprocess
    printf("server proccess start.\n");

    close(exitPipe[1]);

    // start mysql
    MYSQL *mysql = mysql_init(NULL);
    MYSQL *mysql_connect_ret = mysql_real_connect(
        mysql, "localhost", "root", "123", "MyDatabases", 0, NULL, 0);
    ERROR_CHECK(mysql_connect_ret, NULL, "mysql_real_connect");
    printf("mysql connected.\n");

    // 查找用户
    char clientName[] = "testuser1";
    userInfo_t user;
    _find_user(mysql, clientName, &user);
    _print_user(&user);

    printf("MySQL connection closed.\n");

    // get serveer.config = 192.168.238.128 12345 3
    char ip[128] = {0};
    char port[128] = {0};
    int workernum;
    _get_config(ip, port, &workernum);

    // tcp init
    int sockfd = _tcp_init(ip, port);

    // threadPool init & start
    threadPool_t pool;
    threadPool_init(&pool, workernum);

    int epfd = epoll_create(1);
    epollAdd(epfd, sockfd);
    epollAdd(epfd, exitPipe[0]);

    char buf[4096] = {0};
    int netfd = -1;
    struct epoll_event readySet[1024];
    while (1)
    {
        int readyNum = epoll_wait(epfd, readySet, 1024, -1);
        for (int i = 0; i < readyNum; ++i)
        {
            int cfd = readySet[i].data.fd;
            // printf("clientfd = %d\n", cfd);
            if (cfd == sockfd)
            {
                netfd = accept(sockfd, NULL, NULL);
                printf("new connect netfd = %d\n", netfd);
                epollAdd(epfd, netfd);
            }
            else if (cfd == exitPipe[0])
            {
                printf("get SIGUSR1\n");
                write_log("Received SIGUSR1, server closed.");
                mysql_close(mysql);
                pthread_mutex_lock(&pool._mutex);
                pool._exitFlag = 1;
                pthread_cond_broadcast(&pool._cond);
                pthread_mutex_unlock(&pool._mutex);
                for (int i = 0; i < pool._tidArr._worker_num; ++i)
                {
                    pthread_join(pool._tidArr._arr[i], NULL);
                    printf("worker %d exit.\n", i);
                }
                printf("subprocess exit.\n");
                exit(0);
            }
            // clientFd
            else if (cfd != -1)
            {
                // recv msg from client
                ssize_t sret = recvMsg(cfd, buf);
                if (sret <= 0)
                { // if disconnect
                    printf("Client %d disconnected\n", cfd);
                    epollDel(epfd, cfd);
                    continue;
                }
                buf[sret] = '\0';
                // printf("buf = %s\n", buf);
                write_log("Received message from client %d: %s", cfd, buf);

                // make task
                task_t *task =
                    (task_t *)malloc(sizeof(task_t)); // free in deque
                _task_init(task);
                strcpy(task->_data, buf);
                task->_clientFd = cfd;
                write_log("task->_data = %s\n",
                          task->_data); // cout all string in task->_data

                // enqueue
                pthread_mutex_lock(&pool._mutex);
                _taskQueue_enque(&pool._q, task);
                pthread_cond_broadcast(&pool._cond);
                pthread_mutex_unlock(&pool._mutex);
            }
        }
    }

    return 0;
}
